package randomwalk.restricted;

import java.util.ArrayList;
import java.util.HashSet;

import evaluation.EvaluationMetric;

import randomwalk.PreferencesVector;
import randomwalk.QuizSetVerification;
import randomwalk.socialgraph.CompleteUsersTracksGraph;

import lastfm.LastfmDataset;
import lastfm.LastfmTrackTrackSubmatrix;
import lastfm.LastfmUserTrackSubmatrix;
import lastfm.LastfmUserUserSubmatrix;
import musictrackrecommendation.Dataset;
import musictrackrecommendation.ExperimentParameters;

public class RestrictedRandomWalk {
	private int userTopUsersCount = 12;
	private int userTopTracksCount = 12;
	private int friendTopTracksCount = 12;
	private int trackTopTrackCount = 12;

	private ArrayList<Integer> similarUsers;
	private ArrayList<Integer> userTracks;
	//private ArrayList<Integer> allUserTracks;
	private HashSet<Integer> similarTracks;

	public RestrictedRandomWalk(int userTopUsersCount, int userTopTracksCount, 
			int friendTopTracksCount, int trackTopTrackCount) {
		this.userTopUsersCount = userTopUsersCount;
		this.userTopTracksCount = userTopTracksCount;
		this.friendTopTracksCount = friendTopTracksCount;
		this.trackTopTrackCount = trackTopTrackCount;
	}

	public void recommend(int userId) {
		getSimilarItems(userId);
		CompleteUsersTracksGraph socialGraph = getRelationsBetweenItems();
		
		ExperimentParameters parameters = ExperimentParameters.getInstance();
		
		Dataset datasetProperties = parameters.getDatasetProperties();
		
		double restartProbability = parameters.getRestartProbability();
		EvaluationMetric[] metrics = parameters.getMetrics();

		PreferencesVector preferencesVector = filterRestartVector(datasetProperties.getRestartVector(userId));

		QuizSetVerification verification = new QuizSetVerification(userId);
		preferencesVector.normalize();
		
		double[] trackPreferences = socialGraph.randomWalkWithRestarts(
				preferencesVector, restartProbability, verification, userId);

		ArrayList<Integer> topTracks = verification.prepareTopTracks(trackPreferences, 100);

			
		for (EvaluationMetric metric : metrics) {
			metric.addRecommendation(userId, topTracks, verification);
		}
	}

	private void getSimilarItems(int userId) {
		LastfmDataset dataset = new LastfmDataset();
		similarUsers = dataset.getSimilarUsers(userId, userTopUsersCount);
		
		userTracks = dataset.getUserTrackIds(userId, userTopTracksCount);

		similarTracks = new HashSet<Integer>();
		similarTracks.addAll(userTracks);
		
		for (int id : similarUsers) {
			similarTracks.addAll(dataset.getUserTrackIds(id,
					friendTopTracksCount));
		}

		for (int trackId : userTracks) {
			similarTracks.addAll(dataset.getSimilarTracks(trackId, trackTopTrackCount));
		}
	}

	private CompleteUsersTracksGraph getRelationsBetweenItems() {
		LastfmDataset dataset = new LastfmDataset();
		LastfmUserUserSubmatrix userUser = dataset
				.getRestrictedUserUser(similarUsers);
		
		ArrayList<Integer> allTracks = new ArrayList<Integer>();
		allTracks.addAll(similarTracks);
		LastfmUserTrackSubmatrix userTrack = dataset.getRestrictedUserTrack(
				similarUsers, allTracks);
		
		LastfmTrackTrackSubmatrix trackTrack = dataset
				.getRestrictedTrackTrack(allTracks);
		
		return new CompleteUsersTracksGraph(
				userUser,
				userTrack, 
				trackTrack);
	}
	
	private PreferencesVector filterRestartVector(PreferencesVector restartVector) {
		for(int i = 0; i < restartVector.getUsers().length; i++) {
			if(!similarUsers.contains(i))
				restartVector.getUsers()[i] = 0;
		}
		for(int i = 0; i < restartVector.getTracks().length; i++) {
			if(!similarTracks.contains(i))
				restartVector.getTracks()[i] = 0;
		}
		
		return restartVector;
	}
}
